package com.apes.pipeline;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.apes.framework.api.DomainService;
import com.apes.framework.jpa.ApesBean;
import com.apes.framework.jpa.repository.CustomRepository;
import com.apes.framework.jpa.spec.JpaDsl;
import com.apes.framework.jpa.spec.Sorts;
import com.apes.framework.plugin.esb.api.SimpleRequest;
import com.apes.framework.plugin.esb.processor.connector.http.HttpTransporter;
import com.apes.framework.plugin.outbox.OutboxEvent;
import com.apes.framework.util.JpaUtil;
import com.apes.framework.util.MapUtil;
import com.apes.framework.util.ReflectUtil;
import com.apestech.framework.json.JSON;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 功能：数据同步 服务
 *
 * @author xul
 * @create 2020-05-13 19:13
 */
@Service
public class DataPipelineService extends DomainService {

    @Autowired
    private TransactionTemplate transactionTemplate;

    public List inbound(SimpleRequest simpleRequest) throws Exception {
        List<Map> result = new ArrayList<>();
        String model = simpleRequest.get("model");
        CustomRepository repository = JpaUtil.getCustomRepository(model);
        Map request = simpleRequest.getMap();
        int page = 0;
        int size = (int) request.getOrDefault("size", 100);
        Object conditions = null;
        if (request.containsKey("conditions")) {
            conditions = request.get("conditions");
        }
        List<String> excludes = new ArrayList<>();
        if(request.containsKey("excludes")){
            excludes = (List<String>) request.get("excludes");
        }
        HttpTransporter transporter = new HttpTransporter();
        transporter.setUrl((String) request.get("url"));
        while (true) {
            SimpleRequest rqst = new SimpleRequest();
            Map body = MapUtil.mapper("model", model, "page", page, "size", size);
            if (conditions != null) {
                body.put("conditions", conditions);
            }
            rqst.setData(MapUtil.mapper("appKey", "00001", "method", "data.pipeline.outbound", "version", "1.0", "body", JSON.toJSONString(body)));
            String rslt = (String) transporter.process(rqst);
            List rows = (List) JSONObject.parseObject(rslt).get("body");
            List<String> finalExcludes = excludes;
            rows.stream().forEach(row -> {
                finalExcludes.stream().forEach(field -> ((Map) row).remove(field));
                try {
                    transactionTemplate.execute(status -> {
                        Object bean = getBusinessObject(model, row);
                        Serializable id = JpaUtil.getId((ApesBean) bean);
                        Object o = repository.findOne(id);
                        if (o != null) {
                            ReflectUtil.copy(o, bean, "version");
                        }
                        try {
                            repository.save(bean);
                        } catch (Exception e) {
                            status.isRollbackOnly();
                            throw e;
                        }
                        return null;
                    });
                } catch (Exception e) {
                    e.printStackTrace();
                    result.add(MapUtil.mapper("id", ((Map) row).get("id"), "error", e.getMessage()));
                }

            });
            if (rows.size() < size) {
                break;
            }
            page += 1;
        }
        if (model.equals("com.apes.scm.rbac.model.Menu")) {
            invoke("aut.menu.clearMenuCache", new HashMap<>());
        }
        return result;
    }

    public <T> T outbound(SimpleRequest simpleRequest) {
        Map m = simpleRequest.getMap();
        CustomRepository repository = JpaUtil.getCustomRepository((String) m.get("model"));
        String sorts = "lastUpdatedStamp";
        if (m.containsKey("sorts")) {
            sorts = (String) m.get("sorts");
        }
        Pageable pageable = PageRequest.of(simpleRequest.get("page"), simpleRequest.get("size"), Sorts.builder().asc(sorts).build());
        if (m.containsKey("conditions")) {
            Specification<T> criteria = JpaDsl.toCriteria((Map) m.get("conditions"));
            return (T) repository.findAll(criteria, pageable).getContent();
        }
        return (T) repository.findAll(pageable).getContent();
    }

    private Object getBusinessObject(String model, Object payload) {
        try {
            Class clazz = Class.forName(model);
            SimpleRequest sr = new SimpleRequest();
            sr.setData(payload);
            return sr.getO(clazz);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}
